package cn.jbolt.core.base.config;

import cn.hutool.setting.Setting;
import cn.hutool.setting.SettingUtil;
import cn.jbolt.core.actionreport.JBoltActionReportLogWriter;
import cn.jbolt.core.actionreport.JBoltActionReportSystemOutWriter;
import cn.jbolt.core.base.JBoltIDGenMode;
import cn.jbolt.core.bean.JBoltOfModuleInfo;
import cn.jbolt.core.cache.JBoltCacheType;
import cn.jbolt.core.cache.JBoltGlobalConfigCache;
import cn.jbolt.core.cache.redis.JBoltRedisFstSerializer;
import cn.jbolt.core.cache.redis.JBoltRedisSerializerType;
import cn.jbolt.core.consts.JBoltConst;
import cn.jbolt.core.db.dialect.JBoltDMDialect;
import cn.jbolt.core.db.dialect.JBoltMysqlDialect;
import cn.jbolt.core.db.dialect.JBoltPostgresqlDialect;
import cn.jbolt.core.db.dialect.JBoltSqlServerDialect;
import cn.jbolt.core.db.sql.DBType;
import cn.jbolt.core.enumutil.JBoltEnumBean;
import cn.jbolt.core.handler.base.JBoltSaasTenantSnParser;
import cn.jbolt.core.service.JBoltProjectSystemLogProcessor;
import cn.jbolt.core.util.JBoltDesUtil;
import cn.jbolt.core.util.JBoltMethodCaller;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.jfinal.config.Plugins;
import com.jfinal.core.ActionReporter;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.dialect.AnsiSqlDialect;
import com.jfinal.plugin.activerecord.dialect.OracleDialect;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.redis.RedisPlugin;
import com.jfinal.plugin.redis.serializer.FstSerializer;
import com.jfinal.plugin.redis.serializer.FurySerializer;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;

/**
 * JBolt全局配置文件配置参数
 *
 * @ClassName: JBoltConfig
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2022年2月11日
 */
public class JBoltConfig {
	// 当前application的项目运行环境是开发(dev) or 生产(pro)
	public static String PDEV = "dev";
	// 定义项目部署环境是不是始终保持https
	public static boolean NEED_ALWAYS_HTTPS = false;
	// 上传文件保存路径的前缀 默认为空 项目下存 线上 可能会存到项目之外的目录里
	public static String BASE_UPLOAD_PATH_PRE = null;
	//上传文件到服务器本机存储地址 保存的域名端口信息 不包括http schema
	public static String UPLOAD_FILE_DOMAIN = "localhost";
	// 系统运行是否是Demo模式
	public static boolean DEMO_MODE = false;
	// 否是开发模式
	public static boolean DEV_MODE = true;
	// 系统名称
	public static String SYSTEM_NAME = JBoltConst.JBOLT_DEFAULT_SYSTEM_NAME;
	// 平台版权所有人
	public static String SYSTEM_COPYRIGHT_COMPANY = JBoltConst.JBOLT_DEFAULT_SYSTEM_COPYRIGHT_COMPANY;
	// 平台版权所有人链接
	public static String SYSTEM_COPYRIGHT_LINK = JBoltConst.JBOLT_DEFAULT_SYSTEM_COPYRIGHT_LINK;
	//项目系统版本号
	public static String SYSTEM_VERSION = "1.0.0";
	// 主数据源数据库类型
	public static String MAIN_DB_TYPE = DBType.MYSQL;
	// 主数据源数据库名称
	public static String MAIN_DB_NAME = null;
	// 主数据源数据库名称 sqlserver schema
	public static String MAIN_DB_SCHEMA = null;
	// 全局默认ID策略 处理完还找不到的就用它 这个为null 就只能auto
	public static String GLOBAL_DEFAULT_ID_GEN_MODE = JBoltIDGenMode.AUTO;
	// 主数据源核心表默认ID策略
	public static String MAIN_ID_GEN_MODE = null;
	// 主数据源核心表ID策略 强制一致性 默认null 不开启
	public static String MAIN_FORCE_CAST_ALL_ID_GEN_MODE = null;
	// 默认jfinal action report输出writer
	public static String ACTION_REPORT_WRITER = "sysout";
	//action报告是否开启准确的line_number
	public static boolean ACTION_REPORT_LINE_NUMBER_ENABLE = false;
	// 默认Jbolt auto cache debug log
	public static boolean JBOLT_AUTO_CACHE_LOG = false;
	// 默认assets version
	public static String ASSETS_VERSION;
	// 终端ID
	public static long WORKER_ID = 0;
	// 数据中心ID
	public static long DATACENTER_ID = 0;
	// 强制全局主键生成策略 默认null 不启用 特殊情况使用
	public static String FORCE_CAST_GLOBAL_ID_GEN_MODE = null;
	// 项目配置
	public static Prop prop;
	// 项目redis服务端配置
	public static Setting redisSettings;
	// 项目caffeine cache配置
	public static Setting caffeineSettings;
	// 插件配置
	public static Plugins plugins = null;
	// 部署的domain
	public static String DOMAIN = null;
	// word导出时内部资源的domain
	public static String WORD_IMG_INNER_DOMAIN = null;
	// JBolt Websocket Enable 默认开启
	public static boolean JBOLT_WEBSOCKET_ENABLE = true;
	// JBolt 全局强制上传到 local qiniu alioss
	public static String JBOLT_GLOBAL_UPLOAD_TO = "local";
	// JBolt 是否开启sentinel 默认false
	public static boolean JBOLT_SENTINEL_ENABLE = false;
	// JBolt 默认使用什么缓存 默认ehcache
	public static String JBOLT_CACHE_TYPE = JBoltCacheType.CAFFEINE;
	// JBolt 默认cache name
	public static String JBOLT_CACHE_NAME = JBoltConst.JBOLT_CACHE_DEFAULT_NAME;
	// JBolt Druid默认开发模式下输入完整sql
	public static boolean JBOLT_DRUID_DEV_MODE_FULL_SQL_LOG = true;
	//启用全局跨域 默认true
	public static boolean JBOLT_GLOBAL_CROSS_ORIGIN_ENABLE = true;
	//启用PlatformIndexController
	public static boolean PLATFORM_INDEX_CONTROLLER_ENABLE = true;
	//是否启用JBoltApiLogInterceptor 拦截器
	public static boolean PLATFORM_API_LOG_INTERCEPTOR_ENABLE = false;
	//代码生成 可选modules是否包含jbolt核心内置modules 默认false
	public static boolean CODE_GEN_MODULES_INCLUDE_JBOLT_MODULES = false;

	/*****************saas模式相关********************/
	// 项目是否启用了saas模式
	public static boolean SAAS_ENABLE = false;
	// 部署的 租户二级域名 主domain
	public static String SAAS_TENANT_DOMAIN = null;
	// 租户SN解析器类型
	public static String SAAS_TENANT_SN_PARSER = JBoltSaasTenantSnParser.TYPE_DOMAIN;
	// 租户SN KEY 使用default和header模式时有效
	public static String SAAS_TENANT_SN_KEY = JBoltSaasTenantSnParser.DEFAULT_TENANT_SN_KEY;
	// 租户默认数据源
	public static String SAAS_TENANT_DATASOURCE_CONFIG_NAME = DbKit.MAIN_CONFIG_NAME;
	//日志处理器
	private static JBoltProjectSystemLogProcessor jboltProjectSystemLogProcessor = null;
	//是否开启可视化代码设计与生成功能
	public static boolean JBOLT_CODE_GEN_ENABLE = false;
	//是否启用 所有get请求 target 都要处理xss
	public static boolean PROCESS_GET_REQUEST_TARGET_XSS_ENABLE = false;
	//开启验证码 放缓存
	public static boolean CAPTCHA_CACHE_ENABLE = false;
	//是否开启解析json请求参数 action注入 json参数 contentType = application/json的
	public static boolean RESOLVE_JSON_REQUEST_ENABLE = false;
	//是否开启敏感词词库加载与检测
	public static boolean SENSITIVE_WORD_CHECK_ENABLE = false;

	//是否是通过服务器启动 加载
	private static boolean LOAD_BY_SERVER_START = false;

	//是否开启检测有效性 默认不检测 紧急使用
	public static boolean IS_NEED_CHECK_JWT_API_USER_EFFECTIVE = JBoltConst.JBOLT_DEFAULT_CHECK_JWT_API_USER_EFFECTIVE_ENABLE;
	//检测有效性的token 紧急使用
	public static String CHECK_JWT_API_USER_EFFECTIVE_TOKEN = JBoltConst.JBOLT_DEFAULT_CHECK_JWT_API_USER_EFFECTIVE_TOKEN;
	//动态代理使用哪种类型 默认 jfinal_proxy
	public static String JBOLT_PROXY_TYPE = JBoltConst.JBOLT_DEFAULT_PROXY_TYPE;

	//JBolt wechat user 默认头像
	public static String JBOLT_WECHAT_USER_DEFAULT_AVATAR = null;
	//JBolt redis序列化配置 自定义序列化类型
	public static JBoltRedisSerializerType JBOLT_REDIS_SERIALIZER_TYPE = JBoltRedisSerializerType.fury;
	//自定义扩展模块列表
	public static List<JBoltEnumBean> EXTEND_OF_MODULES = Arrays.asList(new JBoltEnumBean("核心模块",JBoltOfModuleInfo.PLATFORM_INNER_ADMIN));
	//自定义扩展模块列表的enum的class name
	public static String EXTEND_OF_MODULE_ENUM_CLASS_SIMPLE_NAME = null;
	//自定义是否支持java.awt.headless模式
	public static Boolean JAVA_AWT_HEADLESS_ENABLE = false;
	//oracle数据库 sql拼接工具类里是否使用双引号
	public static Boolean ORACLE_SQL_QUOTATION_MARK_ENABLE = true;
	//启动时是否校验和初始化新的字典数据
	public static Boolean ONSTART_CHECK_AND_INIT_DICTIONARY_ENABLE = true;


	/**
	 * 是否是生产环境
	 *
	 * @return
	 */
	public static boolean pdevIsPro() {
		return "pro".equalsIgnoreCase(PDEV);
	}
	/**
	 * 是否使用cglib
	 *
	 * @return
	 */
	public static boolean isProxyByCglib() {
		return JBoltConst.JBOLT_PROXY_TYPE_CGLIB.equals(JBOLT_PROXY_TYPE);
	}

	/**
	 * 是否使用Javassist
	 *
	 * @return
	 */
	public static boolean isProxyByJavassist() {
		return JBoltConst.JBOLT_PROXY_TYPE_JAVASSIST.equals(JBOLT_PROXY_TYPE);
	}

	/**
	 * 是否使用jfinal_proxy
	 *
	 * @return
	 */
	public static boolean isProxyByJFinal() {
		return JBoltConst.JBOLT_PROXY_TYPE_JFINAL_PROXY.equals(JBOLT_PROXY_TYPE);
	}

	/**
	 * 加载配置文件
	 */
	public static void loadConfig() {
		if (prop == null) {
			loadApplicationConfig();
			loadBaseConfig();
			loadDbconfig();
			loadSaasConfig();
		}
	}

	/**
	 * 加载应用运行主配置
	 */
	private static void loadApplicationConfig() {
		prop = PropKit.use("application.properties");
		if (prop == null) {
			throw new RuntimeException("application.properties not exist!");
		}
		// 设置系统名称
		SYSTEM_NAME = prop.get("system_name", JBoltConst.JBOLT_DEFAULT_SYSTEM_NAME);
		// 设置平台所有权人
		SYSTEM_COPYRIGHT_COMPANY = prop.get("system_copyright_company", JBoltConst.JBOLT_DEFAULT_SYSTEM_COPYRIGHT_COMPANY);
		// 设置平台所有权人 链接URL
		SYSTEM_COPYRIGHT_LINK = prop.get("system_copyright_link", JBoltConst.JBOLT_DEFAULT_SYSTEM_COPYRIGHT_LINK);
		SYSTEM_VERSION = prop.get("system_version", JBoltConst.JBOLT_VERSION);
		// 读取当前配置的部署环境类型 dev是开发环境 pro是生产环境
		PDEV = prop.get("pdev", "dev").trim();
	}

	/**
	 * 加载项目基础配置
	 */
	private static void loadBaseConfig() {
		if (pdevIsPro()) {
			prop = PropKit.appendIfExists("config-pro.properties");
		} else {
			prop = PropKit.appendIfExists("config.properties");
		}
		// 设置当前节点所在数据中心ID
		DATACENTER_ID = JBoltSnowFlakeIdConfig.getDataCenterId();
		// 设置当前节点所在数据中心中的终端ID
		WORKER_ID = JBoltSnowFlakeIdConfig.getWorkId();
		// 设置当前数据库类型
		MAIN_DB_TYPE = prop.get("db_type", DBType.MYSQL);
		// 设置ID全局默认策略
		GLOBAL_DEFAULT_ID_GEN_MODE = prop.get("global_default_id_gen_mode", JBoltIDGenMode.AUTO);
		// 设置ID全局强制策略
		FORCE_CAST_GLOBAL_ID_GEN_MODE = prop.get("force_cast_global_id_gen_mode");
		// 是否启用HTTPS 这样可以让前端所有静态资源 统一https
		NEED_ALWAYS_HTTPS = prop.getBoolean("need_always_https", false);
		// 设置上传路径前缀 用于存放上传文件到其他绝对路径 而不是项目根路径下
		BASE_UPLOAD_PATH_PRE = prop.get("base_upload_path_pre");
		//上传文件到服务器本机存储地址 保存的域名端口信息 不包括http schema
		UPLOAD_FILE_DOMAIN = prop.get("upload_file_domain","localhost");
		// 当前项目是否是Demo 模式 demo模式很多数据不让删除
		DEMO_MODE = prop.getBoolean("demo_mode", false);
		// 设置当前是否为开发模式
		DEV_MODE = prop.getBoolean("dev_mode", true);
		// DOMAIN
		DOMAIN = prop.get("domain");
		if(StrKit.notBlank(DOMAIN) && (DOMAIN.startsWith("http://") || DOMAIN.startsWith("https://"))) {
			throw new RuntimeException("平台配置文件config"+(pdevIsPro()?"-pro.properties":".properties")+"中domain配置不能带scheme 请删掉http:// or https://");
		}
		//WORD_IMG_INNER_DOMAIN
		WORD_IMG_INNER_DOMAIN=prop.get("word_img_inner_domain");
		if(StrKit.notBlank(WORD_IMG_INNER_DOMAIN) && (WORD_IMG_INNER_DOMAIN.startsWith("http://") || WORD_IMG_INNER_DOMAIN.startsWith("https://"))) {
			throw new RuntimeException("平台配置文件config"+(pdevIsPro()?"-pro.properties":".properties")+"中word_img_inner_domain配置不能带scheme 请删掉http:// or https://");
		}
		// 设置是否系统启用websocket
		JBOLT_WEBSOCKET_ENABLE = prop.getBoolean("jbolt_websocket_enable", true);
		// 设置全局强制上传位置 本地:local 七牛:qiniu 阿里云oss:alioss
		JBOLT_GLOBAL_UPLOAD_TO = prop.get("jbolt_global_upload_to", "local");
		// 设置是否开启sentinel
		JBOLT_SENTINEL_ENABLE = prop.getBoolean("sentinel_enable", false);
		// 设置默认缓存
		JBOLT_CACHE_TYPE = prop.get("jbolt_cache_type", JBoltCacheType.CAFFEINE);
		JBOLT_CACHE_NAME = prop.get("jbolt_cache_name", JBoltConst.JBOLT_CACHE_DEFAULT_NAME);
		//JBolt druid 配置在开发模式下是否开启全sql日志 默认true
		JBOLT_DRUID_DEV_MODE_FULL_SQL_LOG = prop.getBoolean("jbolt_druid_dev_mode_full_sql_log",true);
		//启用全局跨域
		JBOLT_GLOBAL_CROSS_ORIGIN_ENABLE = prop.getBoolean("jbolt_global_cross_origin_enable",true);
		//启用PlatformIndexController
		PLATFORM_INDEX_CONTROLLER_ENABLE = prop.getBoolean("platform_index_controller_enable",true);
		//启用JBoltApiLogInterceptor拦截器
		PLATFORM_API_LOG_INTERCEPTOR_ENABLE = prop.getBoolean("platform_api_log_interceptor_enable",false);
		//代码生成 可选modules是否包含jbolt核心内置modules 默认false
		CODE_GEN_MODULES_INCLUDE_JBOLT_MODULES = prop.getBoolean("code_gen_modules_include_jbolt_modules",false);
		//SAAS_ENABLE
		SAAS_ENABLE = prop.getBoolean("saas_enable", false);
		//可视化设计与代码生成配置读取
		JBOLT_CODE_GEN_ENABLE = prop.getBoolean("jbolt_code_gen_enable",false);
		//是否开启get请求 target处理xss
		PROCESS_GET_REQUEST_TARGET_XSS_ENABLE = prop.getBoolean("process_get_request_target_xss_enable",false);
		//验证码是否启用缓存
		CAPTCHA_CACHE_ENABLE = prop.getBoolean("captcha_cache_enable",false);
		//是否解析json请求参数 contentType=application/json 的 属于jfinal 内置能力 默认不开
		RESOLVE_JSON_REQUEST_ENABLE = prop.getBoolean("resolve_json_request_enable",false);
		//是否开启敏感词词库加载与检测
		SENSITIVE_WORD_CHECK_ENABLE = prop.getBoolean("sensitive_word_check_enable",false);
		//读取配置的JBolt使用的代理类型 默认jfinal_proxy
		JBOLT_PROXY_TYPE = prop.get("jbolt_proxy_type",JBoltConst.JBOLT_PROXY_TYPE_JFINAL_PROXY);
		//读取默认配置微信用户头像
		JBOLT_WECHAT_USER_DEFAULT_AVATAR = prop.get("jbolt_wechat_user_default_avatar");
		//读取默认配置是否开启Jbolt自定义的redis 序列化类型 默认fury
		JBOLT_REDIS_SERIALIZER_TYPE = JBoltRedisSerializerType.valueOf(prop.get("jbolt_redis_serializer_type",JBoltRedisSerializerType.fury.name()));
		//读取是否默认开启JAVA_AWT_HEADLESS模式
		JAVA_AWT_HEADLESS_ENABLE = prop.getBoolean("java_awt_headless_enable",false);
		//oracle数据库 sql拼接工具类里是否使用双引号
		ORACLE_SQL_QUOTATION_MARK_ENABLE = prop.getBoolean("oracle_sql_quotation_mark_enable",true);
		//启动时是否校验和初始化新的字典数据
		ONSTART_CHECK_AND_INIT_DICTIONARY_ENABLE = prop.getBoolean("onstart_check_and_init_dictionary_enable",true);
	}

	/**
	 * 加载著数据源数据库配置
	 */
	private static void loadDbconfig() {
		// 根据MAIN_DB_TYPE 和配置部署环境 加载数据库相关配置文件
		if (pdevIsPro()) {
			prop = PropKit.appendIfExists("dbconfig/" + MAIN_DB_TYPE + "/config-pro.properties");
		} else {
			prop = PropKit.appendIfExists("dbconfig/" + MAIN_DB_TYPE + "/config.properties");
		}
		// 主数据源 数据库名称
		MAIN_DB_NAME = prop.get("db_name");
		// 主数据源 数据库schema 架构
		if(isSqlServer()){
			MAIN_DB_SCHEMA = prop.get("db_schema",JBoltConst.JBOLT_SQLSERVER_SCHEMA_DEFAULT);
		}else{
			MAIN_DB_SCHEMA = prop.get("db_schema");
		}

		// 主数据源 默认策略读取配置
		MAIN_ID_GEN_MODE = prop.get("id_gen_mode");
		// 主数据源强制所有表一致规则 不管model上的tableBind写的啥
		MAIN_FORCE_CAST_ALL_ID_GEN_MODE = prop.get("force_cast_all_id_gen_mode");
	}

	/**
	 * 加载saas架构需要的配置
	 */
	private static void loadSaasConfig() {
		if(!SAAS_ENABLE){
			return;
		}
		if (pdevIsPro()) {
			prop = PropKit.appendIfExists("saas/saas_config-pro.properties");
		} else {
			prop = PropKit.appendIfExists("saas/saas_config.properties");
		}

		//SAAS_TENANT_DOMAIN
		SAAS_TENANT_DOMAIN=prop.get("saas_tenant_domain");
		if(StrKit.notBlank(SAAS_TENANT_DOMAIN) && (SAAS_TENANT_DOMAIN.startsWith("http://") || SAAS_TENANT_DOMAIN.startsWith("https://"))) {
			throw new RuntimeException("平台配置文件config"+(pdevIsPro()?"-pro.properties":".properties")+"中saas_tenant_domain配置不能带scheme 请删掉http:// or https://");
		}
		//SAAS_TENANT_SN_PARSER
		SAAS_TENANT_SN_PARSER=prop.get("saas_tenant_sn_parser", JBoltSaasTenantSnParser.TYPE_DOMAIN);
		//SAAS_TENANT_SN_KEY
		SAAS_TENANT_SN_KEY=prop.get("saas_tenant_sn_key", JBoltSaasTenantSnParser.DEFAULT_TENANT_SN_KEY);
		//SAAS_TENANT_DATASOURCE_CONFIG_NAME
		SAAS_TENANT_DATASOURCE_CONFIG_NAME=prop.get("saas_tenant_datasource_config_name", DbKit.MAIN_CONFIG_NAME);
	}

	/**
	 * 创建一个Druid配置插件
	 *
	 * @return
	 */
	public static DruidPlugin createDruidPlugin() {
		loadConfig();
		String user = prop.get("user");
		String password = prop.get("password");
		boolean is_encrypted = prop.getBoolean("is_encrypted",false);
		if(is_encrypted){
			user = JBoltDesUtil.getDecryptData(user);
			password = JBoltDesUtil.getDecryptData(password);
		}
		DruidPlugin druidPlugin = new DruidPlugin(prop.get("jdbc_url"), user, password);
		if(!DBType.isDM(MAIN_DB_TYPE)){
			// 配置防火墙
			WallFilter wallFilter = new WallFilter(); // 加强数据库安全
			wallFilter.setDbType(MAIN_DB_TYPE);
			if (isOracle()) {
				// oracle关闭FunctionCheck
				WallConfig wallConfig = wallFilter.getConfig();
				if (wallConfig == null) {
					wallConfig = new WallConfig();
					wallFilter.setConfig(wallConfig);
				}
				wallConfig.setFunctionCheck(false);
			}
			druidPlugin.addFilter(wallFilter);
		}
		// 统计监控的过滤器
		StatFilter statFilter = new StatFilter();
		statFilter.setMergeSql(true);
		statFilter.setLogSlowSql(true);
		statFilter.setDbType(MAIN_DB_TYPE);
		statFilter.setSlowSqlMillis(Duration.ofMillis(1000).toMillis());
		// 添加 StatFilter 才会有统计数据
		druidPlugin.addFilter(statFilter);
		if(DEV_MODE && JBOLT_DRUID_DEV_MODE_FULL_SQL_LOG) {
			// 2.日志插件
			// 保存DruidDataSource的监控记录,设置打印日志周期,默认使用DruidDataSourceStatLoggerImpl
			druidPlugin.setTimeBetweenLogStatsMillis(24 * 60 * 60 * 1000);
//			druidPlugin.setConnectionProperties("druid.timeBetweenLogStatsMillis=" + Duration.ofHours(24).toMillis());
			Slf4jLogFilter slf4jLogFilter = new Slf4jLogFilter();
			slf4jLogFilter.setConnectionLogEnabled(false);
			slf4jLogFilter.setResultSetLogEnabled(false);
			slf4jLogFilter.setStatementParameterSetLogEnabled(false);
			slf4jLogFilter.setConnectionLogEnabled(false);
			slf4jLogFilter.setResultSetCloseAfterLogEnabled(false);
			slf4jLogFilter.setConnectionCloseAfterLogEnabled(false);
			slf4jLogFilter.setStatementParameterClearLogEnable(false);
			slf4jLogFilter.setStatementPrepareAfterLogEnabled(false);
			slf4jLogFilter.setStatementPrepareCallAfterLogEnabled(false);
			slf4jLogFilter.setStatementCreateAfterLogEnabled(false);
			slf4jLogFilter.setStatementCloseAfterLogEnabled(false);

			// 设置输出执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteAfterLogEnabled(false);
			// 设置批量操作执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteBatchAfterLogEnabled(false);
			// 设置查询操作执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteQueryAfterLogEnabled(false);
			// 设置更新 插入 删除 操作执行后的日志 带执行耗时等信息
			slf4jLogFilter.setStatementExecuteUpdateAfterLogEnabled(false);
			// 输出完整的SQL 将值替换掉问号，这个仅在开发模式下有效
			slf4jLogFilter.setStatementExecutableSqlLogEnable(true);

			druidPlugin.addFilter(slf4jLogFilter);
		}
		if (MAIN_DB_TYPE.equals(DBType.MYSQL)) {
			// 指定初始化 编码为utf8mb4
			druidPlugin.setConnectionInitSql("set names utf8mb4");
		}
		return druidPlugin;
	}

	/**
	 * 配置JBoltAutoCacheLog
	 */
	public static void configJBoltAutoCacheLog() {
		JBOLT_AUTO_CACHE_LOG = JBoltGlobalConfigCache.me.getJBoltAutoCacheLog();
	}

	/**
	 * 设置依赖服务器启动加载
	 */
	public static void setLoadByServerStart() {
		LOAD_BY_SERVER_START = true;
	}
	/**
	 * 设置依赖服务器启动加载
	 */
	public static boolean isLoadByServerStart() {
		return LOAD_BY_SERVER_START;
	}
	/**
	 * 配置JFinal action Report输出位置
	 */
	public static void configActionReportWriter() {
		// 判断action report输出方式是jboltlog的话 就使用JBolt的日志输出到控制台和文件归档
		ACTION_REPORT_WRITER = JBoltGlobalConfigCache.me.getJFinalActionReportWriter();
		if (ACTION_REPORT_WRITER.equals("jboltlog")) {
			ActionReporter.setWriter(new JBoltActionReportLogWriter());
		} else {
			ActionReporter.setWriter(new JBoltActionReportSystemOutWriter());
		}

	}

	/**
	 * 配置是否显示action report的行号
	 */
	public static void configJBoltActionReportLineNumberEnable() {
		ACTION_REPORT_LINE_NUMBER_ENABLE = JBoltGlobalConfigCache.me.getJBoltActionReportLineNumberEnable();
	}

	/**
	 * 配置微信公众平台
	 */
	public static void configWechat() {
//		ApiConfigKit.setDevMode(prop.getBoolean("wechat_dev_mode", false));
//		WxaConfigKit.setDevMode(prop.getBoolean("wechat_dev_mode", false));
        try {
            JBoltMethodCaller.call("cn.jbolt.wechat.service.JBoltWechatConfigService", "configAllEnable",new Class[0], new Object[0]);
        } catch (Exception e) {
			System.out.println("未检测到JBoltWechatConfigService类，无法启动公众平台配置");
        }
	}

	public static boolean isOracle() {
		return DBType.isOracle(MAIN_DB_TYPE);
	}

	public static boolean isPostgresql() {
		return DBType.isPostgresql(MAIN_DB_TYPE);
	}

	public static boolean isDM() {
		return DBType.isDM(MAIN_DB_TYPE);
	}

	public static boolean isMysql() {
		return DBType.isMysql(MAIN_DB_TYPE);
	}

	public static boolean isSqlServer() {
		return DBType.isSqlServer(MAIN_DB_TYPE);
	}

	/**
	 * 设置方言
	 *
	 * @param dbType
	 * @return
	 */
	public static String getDriverClass(String dbType) {
		String driverClass = null;
		switch (dbType) {
		case DBType.MYSQL:
			driverClass = JdbcConstants.MYSQL_DRIVER_6;
			break;
		case DBType.ORACLE:
			driverClass = JdbcConstants.ORACLE_DRIVER;
			break;
		case DBType.SQLSERVER:
			driverClass = JdbcConstants.SQL_SERVER_DRIVER_SQLJDBC4;
			break;
		case DBType.POSTGRESQL:
			driverClass = JdbcConstants.POSTGRESQL_DRIVER;
			break;
		case DBType.DM:
			driverClass = JdbcConstants.DM_DRIVER;
			break;
		default:
			driverClass = JdbcConstants.MYSQL_DRIVER_6;
			break;
		}
		return driverClass;
	}

	/**
	 * 设置方言
	 *
	 * @param arp
	 */
	public static void setDialect(ActiveRecordPlugin arp) {
		switch (MAIN_DB_TYPE) {
		case DBType.MYSQL:
			arp.setDialect(new JBoltMysqlDialect());
			break;
		case DBType.ORACLE:
			arp.setDialect(new OracleDialect());
			break;
		case DBType.SQLSERVER:
			arp.setDialect(new JBoltSqlServerDialect());
			break;
		case DBType.POSTGRESQL:
			arp.setDialect(new JBoltPostgresqlDialect());
			break;
		case DBType.DM:
			arp.setDialect(new JBoltDMDialect());
			break;
		default:
			arp.setDialect(new AnsiSqlDialect());
			break;
		}
	}

	/**
	 * 配置redis 支持同时配置N个服务端
	 *
	 * @param me
	 */
	protected static void configRedis(Plugins me) {
		String settingFileName = "redis/redis.setting";
		if (pdevIsPro()) {
			settingFileName = "redis/redis-pro.setting";
		}
		redisSettings = SettingUtil.get(settingFileName);
		if (redisSettings == null || redisSettings.isEmpty()) {
			throw new RuntimeException("redis 配置文件 " + settingFileName + "中未找到有效的redis服务端配置");
		}
		redisSettings.getGroups().forEach(group -> configRedisServer(me, group, redisSettings.getSetting(group)));
	}

	/**
	 * 配置Caffeine 支持同时配置N个
	 *
	 * @param me
	 */
	protected static void configCaffeine(Plugins me) {
		String settingFileName = "caffeine/config.setting";
		if (pdevIsPro()) {
			settingFileName = "caffeine/config-pro.setting";
		}
		caffeineSettings = SettingUtil.get(settingFileName);
		if (caffeineSettings == null || caffeineSettings.isEmpty()) {
			throw new RuntimeException("caffeine 配置文件 " + caffeineSettings + "中未找到有效的caffeine 缓存配置");
		}
	}

	/**
	 * 初始化一个redis 服务端的redisPlugin
	 *
	 * @param me
	 * @param cacheName
	 * @param redisSetting
	 */
	private static void configRedisServer(Plugins me, String cacheName, Setting redisSetting) {
		if (StrKit.isBlank(cacheName) || redisSetting == null || redisSetting.isEmpty()) {
			throw new RuntimeException("redis 配置文件 " + redisSetting.getSettingPath() + "中[" + cacheName + "]配置不能为空");
		}
		boolean enable = redisSetting.getBool("enable");
		if (!enable) {
			return;
		}
		String host = redisSetting.getStr("host");
		if (StrKit.isBlank(host)) {
			throw new RuntimeException(
					"redis 配置文件 " + redisSetting.getSettingPath() + "中[" + cacheName + "]配置[host]不能为空");
		}
		String password = redisSetting.getStr("password");
//		if (StrKit.isBlank(password)) {
//			throw new RuntimeException(
//					"redis 配置文件 " + redisSetting.getSettingPath() + "中[" + cacheName + "]配置[password]不能为空");
//		}
		int port = redisSetting.getInt("port", Protocol.DEFAULT_PORT);
		int timeout = redisSetting.getInt("timeout", Protocol.DEFAULT_TIMEOUT);
		String clientName = redisSetting.getStr("clientName");
		Integer database = redisSetting.getInt("database");
		RedisPlugin redisPlugin = null;
		if (database != null && StrKit.notBlank(clientName)) {
			redisPlugin = new RedisPlugin(cacheName, host, port, timeout, password, database, clientName);
		} else if (database != null && StrKit.isBlank(clientName)) {
			redisPlugin = new RedisPlugin(cacheName, host, port, timeout, password, database);
		} else {
			redisPlugin = new RedisPlugin(cacheName, host, port, timeout, password);
		}

		redisPlugin.config(c->{
			int maxTotal = redisSetting.getInt("maxTotal", JedisPoolConfig.DEFAULT_MAX_TOTAL);
			c.setMaxTotal(maxTotal);

			int maxIdle = redisSetting.getInt("maxIdle", JedisPoolConfig.DEFAULT_MAX_IDLE);
			c.setMaxIdle(maxIdle);

			int minIdle = redisSetting.getInt("minIdle", JedisPoolConfig.DEFAULT_MIN_IDLE);
			c.setMinIdle(minIdle);

			long maxWaitMillis = redisSetting.getLong("maxWaitMillis", JedisPoolConfig.DEFAULT_MAX_WAIT_MILLIS);
			c.setMaxWait(Duration.ofMillis(maxWaitMillis));

			boolean blockWhenExhausted = redisSetting.getBool("blockWhenExhausted", JedisPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED);
			c.setBlockWhenExhausted(blockWhenExhausted);

			boolean testWhileIdle = redisSetting.getBool("testWhileIdle", JedisPoolConfig.DEFAULT_TEST_WHILE_IDLE);
			c.setTestWhileIdle(testWhileIdle);

			long timeBetweenEvictionRunsMillis = redisSetting.getLong("timeBetweenEvictionRunsMillis", JedisPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
			c.setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));

			long minEvictableIdleTimeMillis = redisSetting.getLong("minEvictableIdleTimeMillis", JedisPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
			c.setMinEvictableIdleTime(Duration.ofMillis(minEvictableIdleTimeMillis));
		});

		switch (JBOLT_REDIS_SERIALIZER_TYPE) {
			case fst:
				redisPlugin.setSerializer(FstSerializer.me);
				break;
			case fury:
				redisPlugin.setSerializer(FurySerializer.me);
				break;
			default:
				redisPlugin.setSerializer(JBoltRedisFstSerializer.me);
		}

		me.add(redisPlugin);
	}
	/**
	 * 获取项目二开使用的日志处理器
	 * @return
	 */
	public static JBoltProjectSystemLogProcessor getProjectSystemLogProcessor() {
		return jboltProjectSystemLogProcessor;
	}
	/**
	 * 设置项目二开使用的日志处理器
	 * @param processor
	 */
	public static void setProjectSystemLogProcessor(JBoltProjectSystemLogProcessor processor) {
		jboltProjectSystemLogProcessor = processor;
	}

}
